# -*- coding: utf-8 -*-
"""
@Time    : 2020/8/3 17:55
@Author  : Corey
"""
from PyQt5.QtCore import QRunnable, QWaitCondition, QMutex, pyqtSignal, QObject, QMutexLocker
from ATS.proberdriver.cascade_prober import CascadeProber
from ATS.application.LASER_App.L8164B_App import L8164B_App
import time
import random
from collections import namedtuple
from utils.log_util import loggings


class Signal(QObject):
    TestSignal = pyqtSignal(int)
    send_map = pyqtSignal(object)
    Stop = pyqtSignal(int)
    End = pyqtSignal(int)
    err_signal = pyqtSignal(object)
    wafer_result_signal = pyqtSignal(object, object)


class ProbeStationThread(QRunnable):
    def __init__(self, probe_address, test_seq=None, subdie_list=None,
                 probe_order_list=None):  # , path_folder, file_name
        super().__init__()
        self.cond = QWaitCondition()
        self.mutex = QMutex()
        self.sign = Signal()
        self.test_seq = test_seq
        self.subdie_list = subdie_list
        self.ml = None
        self._isPause = False
        self.is_go_next_subdie = False
        self.pro_address = probe_address
        self.lower_limit = -50  ##对光阈值下限
        self.delay_time = 0.2
        self.probe_delay = 0.2  ##抬针延迟时间
        self.flag = True
        self.singal_pd_dark = False
        self.probe_order_list = probe_order_list

        test_pro_list = set([test.test_pro for test in test_seq])
        test_subdie = set([test.subdie for test in test_seq])
        if len(test_pro_list) == 1 and list(test_pro_list)[0] == "MPD_I_dark":
            self.singal_pd_dark = True
            L8164B_App("SS3").output_off()
        else:
            L8164B_App("SS3").output_on()

        self.test_index = sorted([self.subdie_list.index(test_s) + 1 for test_s in test_subdie])
        self.cp = CascadeProber(self.pro_address)
        self.map_info = namedtuple("map_info", "DieX,DieY,CurSite,CurDie,DiesCount,SubdieLabel")

    def send_message_to_gui(self):
        result = self.cp.read_map_position()
        self.wafer_die_count = int(self.cp.get_wafer_info().DiesCount)
        self.subdie_label_list = []
        for i in range(result.LastSiteIndex):
            if self.cp.get_subdie_status(i) == "E":
                self.subdie_label_list.append(i)

        self.sign.wafer_result_signal.emit(self.wafer_die_count, self.subdie_label_list)

    def run(self):
        try:
            self.send_message_to_gui()
            if self.ml is None:
                self.ml = QMutexLocker(self.mutex)
            if self.probe_order_list is None:
                self.probe_order_list = ["P1", "P2", "H2", "H1"]
            probe_reverse_list = list(reversed(self.probe_order_list))
            self.separation_probes()
            self.move_probes_to_home(probe_reverse_list)
            self.cp.go_to_wafer_home()
            self.cp.move_chuck_contact()
            self.cp.step_first_die()
            if not self.singal_pd_dark:
                self.contact_probes()
                self.set_electric_probes_home()
                self.find_area_recenter()
                self.set_optical_probes_home()
            # while self.flag:
            for die_number in range(self.wafer_die_count):
                if self.flag:
                    if die_number != 0:
                        if not self.singal_pd_dark:
                            self.contact_probes()
                            self.find_area_recenter()
                            self.set_optical_probes_home()
                    for site in self.subdie_label_list:
                        if self.flag:
                            if len(self.subdie_label_list) > 1 and site != 0:
                                self.cp.step_next_subdie(site)
                                if not self.singal_pd_dark:
                                    self.contact_probes()
                                    self.find_area_recenter()
                                    self.set_optical_probes_home()
                            velox_subdie_label = self.cp.get_subdie_label(site)
                            rsp = self.cp.read_map_position()
                            self.sign.send_map.emit(
                                self.map_info(rsp.DieX, rsp.DieY, rsp.CurSite, rsp.CurDie, rsp.DiesCount,
                                              velox_subdie_label))
                            # for item in range(1, self.sip_subdie_number + 1):
                            if not self.singal_pd_dark:
                                for item in self.test_index:
                                    if self.flag:
                                        if self._isPause:
                                            # self.cond.wait(self.ml.mutex())
                                            self.pause()
                                        for probe in self.probe_order_list:
                                            if item != 1:
                                                self.cp.move_optical_subdie_pos(item, probe)
                                        self.find_optical_probes_height()
                                        number = 0
                                        while True:
                                            as_result = self.cp.area_scan()
                                            if float(as_result[-1]) < self.lower_limit and float(
                                                    as_result[-2]) < self.lower_limit:
                                                if number < 3:
                                                    number += 1
                                                    continue
                                                else:
                                                    # self.is_go_next_subdie = True
                                                    # self.sign.err_signal.emit("Area Scan没有找到光")
                                                    self.cp.bin_map_die(1)
                                                    break
                                            else:
                                                # self.is_go_next_subdie = False
                                                break
                                        # if not self.is_go_next_subdie:
                                        if self.flag:
                                            self.sign.TestSignal.emit(1)
                                            self.pause()
                                        else:
                                            self.separation_move_hone(probe_reverse_list)
                                            return

                                    else:
                                        loggings.info("probe_move")
                                        self.separation_move_hone(probe_reverse_list)
                                        return
                                self.separation_probes()
                                self.move_probes_to_home(probe_reverse_list)
                                # self.contact_probes()
                            else:
                                self.contact_single_probe()
                                self.sign.TestSignal.emit(1)
                                self.pause()
                        else:
                            loggings.info("subdie_move")
                            self.separation_move_hone(probe_reverse_list)
                            return

                    self.cp.step_next_die()
                else:
                    loggings.info("die_move")
                    self.separation_move_hone(probe_reverse_list)
                    return
            self.ml.unlock()
        except Exception as e:
            try:
                if "703" in str(e):
                    self.sign.End.emit(1)
                else:
                    self.sign.err_signal.emit(str(e))
                loggings.error(f"ProbeStationThread,{e}")
                self.separation_probes_and_chuck()
                self.move_probes_to_home(probe_reverse_list)
                self.separation_chuck()
            except Exception as e:
                loggings.error(f"ProbeStationThread_separation_probes_and_chuck,{e}")
                self.sign.err_signal.emit(str(e))
        finally:
            try:
                self.separation_probes_and_chuck()
                self.move_probes_to_home(probe_reverse_list)
            except Exception as e:
                loggings.error(f"ProbeStationThread_separation_probes_and_chuck,{e}")
            L8164B_App("SS3").output_off()

    def separation_move_hone(self, probe_reverse_list):
        if len(probe_reverse_list):
            loggings.info("probe stop")
            self.separation_probes_and_chuck()
            self.move_probes_to_home(probe_reverse_list)

    def separation_probes_and_chuck(self):
        self.separation_probes()
        self.separation_chuck()

    def find_area_recenter(self):
        self.find_optical_probes_height()
        self.cp.area_scan()
        self.recenter_optical_probes()
        as_result = self.cp.area_scan()
        if float(as_result[-1]) < self.lower_limit and float(as_result[-2]) < self.lower_limit:
            self.sign.err_signal.emit("Area Scan没有找到光")

    def set_electric_probes_home(self):
        self.cp.set_probe_home(1)
        self.cp.set_probe_home(2)

    def contact_single_probe(self, probe_index=1):
        self.cp.move_probe_contact(probe_index)

    def separation_single_probe(self, probe_index=1):
        self.cp.move_probe_separation(probe_index)

    def recenter_optical_probes(self):
        self.cp.recenter_optical_probe("W")
        time.sleep(self.delay_time)
        self.cp.recenter_optical_probe("E")
        time.sleep(self.delay_time)

    def find_optical_probes_height(self):
        self.cp.find_optical_probe_height("H1")
        time.sleep(self.delay_time)
        self.cp.find_optical_probe_height("H2")
        time.sleep(self.delay_time)

    def set_optical_probes_home(self):
        self.cp.set_optical_probe_home("H1")
        time.sleep(self.delay_time)
        self.cp.set_optical_probe_home("H2")
        time.sleep(self.delay_time)

    def move_probes_to_home(self, probe_list):
        if len(probe_list):
            for probe in probe_list:
                if "H" in probe:
                    self.cp.move_optical_probe_home(probe)
                if "P" in probe:
                    self.cp.move_probe_home(int(probe[-1]))

    def set_optical_probes_height(self):
        self.cp.set_optical_probe_height("H1")
        time.sleep(self.delay_time)
        self.cp.set_optical_probe_height("H2")
        time.sleep(self.delay_time)

    def contact_probes(self):
        self.cp.move_optical_probe_height("H1")
        time.sleep(self.probe_delay)
        if self.cp.get_optical_probe_status("H1")[2] == "0":
            self.cp.move_optical_probe_height("H1")

        self.cp.move_optical_probe_height("H2")
        time.sleep(self.probe_delay)
        if self.cp.get_optical_probe_status("H2")[2] == "0":
            self.cp.move_optical_probe_height("H2")

        self.cp.move_probe_contact(1)
        time.sleep(self.probe_delay)
        if self.cp.read_probe_status(1).PresetHeight == "S":
            self.cp.move_probe_contact(1)

        self.cp.move_probe_contact(2)
        time.sleep(self.probe_delay)
        if self.cp.read_probe_status(2).PresetHeight == "S":
            self.cp.move_probe_contact(2)

    def separation_probes(self):
        self.cp.move_optical_separation_height("H1")
        time.sleep(self.probe_delay)
        if self.cp.get_optical_probe_status("H1")[2] == "1":
            self.cp.move_optical_separation_height("H1")
        self.cp.move_optical_separation_height("H2")
        time.sleep(self.probe_delay)
        if self.cp.get_optical_probe_status("H2")[2] == "1":
            self.cp.move_optical_separation_height("H2")

        self.cp.move_probe_separation(1)
        time.sleep(self.probe_delay)
        if self.cp.read_probe_status(1).PresetHeight == "C":
            self.cp.move_probe_separation(1)

        self.cp.move_probe_separation(2)
        time.sleep(self.probe_delay)
        if self.cp.read_probe_status(2).PresetHeight == "C":
            self.cp.move_probe_separation(2)

    def separation_chuck(self):
        self.cp.move_chuck_separation()

    def pause(self):
        # self.ml.relock()
        self.cond.wait(self.ml.mutex())
        # self._isPause = True

    def resume(self):
        # self.ml.relock()
        self._isPause = False
        time.sleep(0.5)
        self.cond.wakeAll()

    def stop_sip_tools(self):
        self.cp.stop_sip_tools()

    def pause_thread(self):
        # self.ml.relock()
        self._isPause = True

    def resume_thread(self):
        self._isPause = False
        self.resume()

    def cancel_thread(self):
        # self.ml.unlock()
        # self.resume()
        self.flag = False
        self._isPause = False

